package
{
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	
	import mx.core.ILayoutElement;
	
	import spark.layouts.supportClasses.LayoutBase;

	public class RobertFishEyeLayout extends LayoutBase
	{
		private var cursorX:Number;
		private var cursorY:Number;
		
		private var matrices:Vector.<Matrix>;
		
		public function RobertFishEyeLayout()
		{
			super();
		}
		
		override public function updateDisplayList(containerWidth:Number, containerHeight:Number):void
		{
			var rows:Number = 0;
			var columns:Number = 0;
			var blockHeight:Number = 0;
			var blockWidth:Number = 0;
			var blockY:Number = 0;
			var blockX:Number = 0;
			var elementHeight:Number = 0;
			var elementWidth:Number = 0;
			var elementY:Number = 0;
			var elementX:Number = 0;
			var elementScale:Number = 1.0;
			
			super.updateDisplayList(containerWidth, containerHeight);
			
			if (!target) {
				return;
			}
			/*
			{ column * row = target.numElements
			{ column / row = containerWidth / containerHeight
			=>
			{ column = target.numElements / row
			{ target.numElements / (row * row) = containerWidth / containerHeight
			=>
			{ column = target.numElements / row
			{ row = sqrt(target.numElements * containerHeight / containerWidth)
			*/
			rows = Math.floor(Math.sqrt(target.numElements * containerHeight / containerWidth) + 0.5);
			columns = Math.ceil(target.numElements / rows);
			blockHeight = containerHeight / rows;
			blockWidth = containerWidth / columns;
			
			trace(containerWidth, containerHeight, rows, columns, blockWidth, blockHeight);
			
			for (var i:int = 0; i < target.numElements; i++) {
				var element:ILayoutElement = target.getElementAt(i);
				var m:Matrix = element.getLayoutMatrix();
				var scale:Number = 1;
				
				blockY = blockHeight * Math.floor(i / columns);
				blockX = blockWidth * (i % columns);
				
				if(cursorX >= 0 && cursorY >= 0) {
					var distance:Number = distance(target.contentMouseX, target.contentMouseY, blockX + blockWidth / 2, blockY + blockHeight / 2);
					scale += 3 * normalDistribution(distance, 0, 100) / normalDistribution(0, 0, 100);
				}
				
				if(element.getPreferredBoundsWidth() < element.getPreferredBoundsHeight()) {
					elementHeight = scale * blockHeight / 4;
					elementWidth = elementHeight * element.getPreferredBoundsWidth() / element.getPreferredBoundsHeight();
				} else {
					elementWidth = scale * blockWidth / 4;
					elementHeight = elementWidth * element.getPreferredBoundsHeight() / element.getPreferredBoundsWidth();
				}
				element.setLayoutBoundsSize(elementWidth, elementHeight);
				
				elementY = (blockY + blockHeight / 2) - (elementHeight / 2);
				elementX = (blockX + blockWidth / 2) - (elementWidth / 2);
				
				m.identity();
				m.translate(elementX, elementY);
				element.setLayoutMatrix(m, false);
			}
		}
		
		public function normalDistribution(x:Number, mean:Number, deviation:Number):Number
		{
			return Math.exp((mean - x) / (2 * deviation)) / (deviation * Math.sqrt(2 * Math.PI));
		}
		
		public function distance(x1:Number, y1:Number, x2:Number, y2:Number):Number
		{
			return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
		}
		
		public function onMouseMove(event:MouseEvent): void
		{
			cursorX = target.contentMouseX;
			cursorY = target.contentMouseY;
			target.invalidateDisplayList();
		}
		
		public function onRollOut(event:MouseEvent): void
		{
			cursorX = -1;
			cursorY = -1;
			target.invalidateDisplayList();
		}
	}
}